package main

import (
  "fmt"
  "sync"
  "net"
)

type Server struct {
  Ip string
  Port int
  // broadcast channel
  Message chan string
  // sync lock
  mapLock sync.RWMutex
  // user lists
  OnlineMap map[string] *User
}

func CreateServer(ip string, port int)(*Server){
  return &Server {
    Ip: ip,
    Port: port,
    Message: make(chan string),
    OnlineMap: make(map[string]*User),
  }
}

func(this *Server)ListenMessager(){
  for {
    msg := <- this.Message

    this.mapLock.Lock()
    for _,user := range this.OnlineMap {
      user.C <- msg
      //fmt.Println("new message to user.", user, msg)
    }
    this.mapLock.Unlock()
  }
}

func(this *Server)Broadcast(user *User, msg string){
  Msg := "[" + user.Addr + "]" + user.Name + ":" + msg
  
  this.Message <- Msg
}

func(this *Server)Handle(conn net.Conn){

  user := NewUser(conn)
  //fmt.Println("socket connected. user: ",user)

  this.mapLock.Lock()
  this.OnlineMap[user.Name] = user
  this.mapLock.Unlock()

  this.Broadcast(user, "online.")

  select {}
}

func(this *Server)Start(){
  listenner,err := net.Listen("tcp", fmt.Sprintf("%s:%d",this.Ip,this.Port))
  if err != nil {
    fmt.Println("net.Listen err: ",err)
    return
  }

  defer listenner.Close()

  go this.ListenMessager()
  //
  for {
    conn,err := listenner.Accept()
    if err != nil {
      fmt.Println("net.Accept err: ",err)
      continue
    }
    go this.Handle(conn)
  }
}
